/* FCE Ultra - NES/Famicom Emulator
 *
 * Copyright notice for this file:
 *  Copyright (C) 2002 Xodnizel
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "state.c"      /* Save/Load state AS */

extern char *md5_asciistr(uint8 digest[16]);
extern FCEUGI *FCEUGameInfo;
extern int EnableRewind;

void DSMFix(UINT msg)
{
 switch(msg)
 {
    case WM_VSCROLL:
    case WM_NCRBUTTONDOWN:
    case WM_NCMBUTTONDOWN:
    case WM_NCLBUTTONDOWN:
    case WM_ENTERMENULOOP:StopSound();break;
 }
}
static void ConfigGUI(void);
static void ConfigTiming(void);
static void ConfigPalette(void);
static void ConfigDirectories(void);

static HMENU fceumenu=0;

static int tog=0;
static int CheckedAutoFirePattern=40004;
static int CheckedAutoFireOffset=40016;
static int EnableBackgroundInput=0;
static int MemToolsUpdateSpeed=100;
static int CheckedMemToolsUpdateSpeed=40031;
static int EnablePauseAfterPlayback=0;
static int EnableStopMessageInAvi=0;

void ShowCursorAbs(int w)
{
 static int stat=0;
 if(w)
 {
  if(stat==-1) {stat++; ShowCursor(1);}
 }
 else
 {
  if(stat==0) {stat--; ShowCursor(0);}
 }
}


void CalcWindowSize(RECT *al)
{
 al->left=0;
 al->right=VNSWID*winsizemulx;
 al->top=0;
 al->bottom=totallines*winsizemuly;

 AdjustWindowRectEx(al,GetWindowLong(hAppWnd,GWL_STYLE),GetMenu(hAppWnd)!=NULL,GetWindowLong(hAppWnd,GWL_EXSTYLE));

 al->right-=al->left;
 al->left=0;
 al->bottom-=al->top;
 al->top=0;
}


void RedoMenuGI(FCEUGI *gi)
{
 int simpled[]={101,111,110,200,201,204,203,141,142,143,151,152,300,40003,40028, 0};
 int x;

 x = 0;
 while(simpled[x])
 {
  #ifndef FCEUDEF_DEBUGGER
  if(simpled[x] == 203)
   EnableMenuItem(fceumenu,simpled[x],MF_BYCOMMAND | MF_GRAYED);
  else
  #endif
  #ifndef _USE_SHARED_MEMORY_
  if(simpled[x] == 40002 || simpled[x] == 40003)
	  EnableMenuItem(fceumenu,simpled[x],MF_BYCOMMAND| MF_GRAYED);
  else
  #endif
  EnableMenuItem(fceumenu,simpled[x],MF_BYCOMMAND | (gi?MF_ENABLED:MF_GRAYED));
  x++;
 }
}

void UpdateMenu(void)
{
	static int *polo[3]={&genie,&palyo,&status_icon};
	static int polo2[3]={310,311,303};
	int x;

	for(x=0;x<3;x++)
		CheckMenuItem(fceumenu,polo2[x],*polo[x]?MF_CHECKED:MF_UNCHECKED);

	if(eoptions&EO_BGRUN)
		CheckMenuItem(fceumenu,301,MF_CHECKED);
	else
		CheckMenuItem(fceumenu,301,MF_UNCHECKED);

	if(FCEU_BotMode())
		CheckMenuItem(fceumenu,40003, MF_CHECKED);
	else
		CheckMenuItem(fceumenu,40003, MF_UNCHECKED);

	if(GetAutoFireDesynch())
		CheckMenuItem(fceumenu,40025, MF_CHECKED);
	else
		CheckMenuItem(fceumenu,40025, MF_UNCHECKED);

	CheckMenuItem(fceumenu,302, EnableBackgroundInput?MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(fceumenu,40029, EnableRewind?MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(fceumenu,40034, EnablePauseAfterPlayback?MF_CHECKED:MF_UNCHECKED);
	CheckMenuItem(fceumenu,40035, EnableStopMessageInAvi?MF_CHECKED:MF_UNCHECKED);

	int AutoFirePatternIDs[]={40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40022,40023,40024,0};
	int AutoFireOffsetIDs[]={40016,40017,40018,40019,40020,40021,0};

	x = 0;
	while(AutoFirePatternIDs[x])
	{
		CheckMenuItem(fceumenu,AutoFirePatternIDs[x],
			AutoFirePatternIDs[x]==CheckedAutoFirePattern?MF_CHECKED:MF_UNCHECKED);
		x++;
	}

	x = 0;
	while(AutoFireOffsetIDs[x])
	{
		CheckMenuItem(fceumenu,AutoFireOffsetIDs[x],
			AutoFireOffsetIDs[x]==CheckedAutoFireOffset?MF_CHECKED:MF_UNCHECKED);
		x++;
	}
	
	int MemToolsUpdateSpeedIDs[]={40031,40032,40033,0};
	int MemToolsUpdateSpeedOptions[]={100,25,999,0};
	x = 0;
	while(MemToolsUpdateSpeedIDs[x])
	{
		CheckMenuItem(fceumenu,MemToolsUpdateSpeedIDs[x],
			MemToolsUpdateSpeedOptions[x]==MemToolsUpdateSpeed?MF_CHECKED:MF_UNCHECKED);
		x++;
	}
}

void FCEUD_UpdateLuaMenus()
{
	MENUITEMINFO mii;
	ZeroMemory( &mii, sizeof( mii));
	mii.cbSize = sizeof( mii);
	mii.fMask = MIIM_STATE;
	mii.fState = MFS_UNCHECKED;
	SetMenuItemInfo (fceumenu, 40036, FALSE, &mii);
	if (!FCEU_LuaRunning()) mii.fState |= MFS_DISABLED;
	SetMenuItemInfo (fceumenu, 40037, FALSE, &mii);
}

static HMENU recentmenu, recentdmenu;
char *rfiles[10]={0,0,0,0,0,0,0,0,0,0};
char *rdirs[10]={0,0,0,0,0,0,0,0,0,0};

void UpdateRMenu(HMENU menu, char **strs, int mitem, int baseid)
{
 MENUITEMINFO moo;
 int x;

 moo.cbSize=sizeof(moo);
 moo.fMask=MIIM_SUBMENU|MIIM_STATE;

 GetMenuItemInfo(GetSubMenu(fceumenu,0),mitem,FALSE,&moo);
 moo.hSubMenu=menu;
 moo.fState=strs[0]?MFS_ENABLED:MFS_GRAYED;

 SetMenuItemInfo(GetSubMenu(fceumenu,0),mitem,FALSE,&moo);

 for(x=0;x<10;x++)
  RemoveMenu(menu,baseid+x,MF_BYCOMMAND);
 for(x=9;x>=0;x--)
 {
  char tmp[128+5];
  if(!strs[x]) continue;

  moo.cbSize=sizeof(moo);
  moo.fMask=MIIM_DATA|MIIM_ID|MIIM_TYPE;

  if(strlen(strs[x])<128)
  {
   sprintf(tmp,"&%d. %s",(x+1)%10,strs[x]);
  }
  else
   sprintf(tmp,"&%d. %s",(x+1)%10,strs[x]+strlen(strs[x])-127);

  moo.cch=strlen(tmp);
  moo.fType=0;
  moo.wID=baseid+x;
  moo.dwTypeData=tmp;
  InsertMenuItem(menu,0,1,&moo);
 }
 DrawMenuBar(hAppWnd);
}

void AddRecent(char *fn)
{
 int x;

 for(x=0;x<10;x++)
  if(rfiles[x])
   if(!strcmp(rfiles[x],fn))    // Item is already in list.
   {
    int y;
    char *tmp;

    tmp=rfiles[x];              // Save pointer.
    for(y=x;y;y--)
     rfiles[y]=rfiles[y-1];     // Move items down.

    rfiles[0]=tmp;              // Put item on top.
    UpdateRMenu(recentmenu, rfiles, 102, 600);
    return;
   }

 if(rfiles[9]) free(rfiles[9]);
 for(x=9;x;x--) rfiles[x]=rfiles[x-1];
 rfiles[0]=malloc(strlen(fn)+1);
 strcpy(rfiles[0],fn);
 UpdateRMenu(recentmenu, rfiles, 102, 600);
}

void AddRecentDir(char *fn)
{
 int x;

 for(x=0;x<10;x++)
  if(rdirs[x])
   if(!strcmp(rdirs[x],fn))    // Item is already in list.
   {
    int y;
    char *tmp;

    tmp=rdirs[x];              // Save pointer.
    for(y=x;y;y--)
     rdirs[y]=rdirs[y-1];     // Move items down.

    rdirs[0]=tmp;              // Put item on top.
    UpdateRMenu(recentdmenu, rdirs, 103, 700);
    return;
   }

 if(rdirs[9]) free(rdirs[9]);
 for(x=9;x;x--) rdirs[x]=rdirs[x-1];
 rdirs[0]=malloc(strlen(fn)+1);
 strcpy(rdirs[0],fn);
 UpdateRMenu(recentdmenu, rdirs, 103, 700);
}



void HideMenu(int h)
{
  if(h)
  {
   SetMenu(hAppWnd,0);
  }
  else
  {
   SetMenu(hAppWnd,fceumenu);
  }
}

static LONG WindowXC=1<<30,WindowYC;
void HideFWindow(int h)
{
 LONG desa;

 if(h)  /* Full-screen. */
 {
   RECT bo;
   GetWindowRect(hAppWnd,&bo);
   WindowXC=bo.left;
   WindowYC=bo.top;

   SetMenu(hAppWnd,0);
   desa=WS_POPUP|WS_CLIPSIBLINGS;
 }
 else
 {
   desa=WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS;
   HideMenu(tog);
   /* Stupid DirectDraw bug(I think?) requires this.  Need to investigate it. */
   SetWindowPos(hAppWnd,HWND_NOTOPMOST,0,0,0,0,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOREPOSITION|SWP_NOSIZE);
 }

 SetWindowLong(hAppWnd,GWL_STYLE,desa|(GetWindowLong(hAppWnd,GWL_STYLE)&WS_VISIBLE));
 SetWindowPos(hAppWnd,0,0,0,0,0,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOREPOSITION|SWP_NOSIZE|SWP_NOZORDER);
}

void ToggleHideMenu(void)
{ 
 extern FCEUGI *FCEUGameInfo;
 if(!fullscreen && (FCEUGameInfo || tog))
 {
  tog^=1;
  HideMenu(tog);
  SetMainWindowStuff();
 }
}

void FCEUD_HideMenuToggle(void)
{
	ToggleHideMenu();
}

static void ALoad(char *nameo)
{
  if((GI=FCEUI_LoadGame(nameo,1)))
  {
   palyo=FCEUI_GetCurrentVidSystem(0,0);
   UpdateMenu();
   FixFL();
   SetMainWindowStuff();
   AddRecent(nameo);
   RefreshThrottleFPS();
   if(eoptions&EO_HIDEMENU && !tog)
    ToggleHideMenu();
   if(eoptions&EO_FSAFTERLOAD)
    SetFSVideoMode();
  }
  else
   StopSound();
  ParseGIInput(GI);
  RedoMenuGI(GI);
}

void LoadNewGamey(HWND hParent, char *initialdir)
{
 const char filter[]="All usable files(*.nes,*.nsf,*.fds,*.unf,*.zip,*.gz)\0*.nes;*.nsf;*.fds;*.unf;*.zip;*.gz\0All non-compressed usable files(*.nes,*.nsf,*.fds,*.unf)\0*.nes;*.nsf;*.fds;*.unf\0All files (*.*)\0*.*\0";
 char nameo[2048];
 OPENFILENAME ofn;
 memset(&ofn,0,sizeof(ofn));
 ofn.lStructSize=sizeof(ofn);
 ofn.hInstance=fceu_hInstance;
 ofn.lpstrTitle="FCE Ultra Open File...";
 ofn.lpstrFilter=filter;
 nameo[0]=0;
 ofn.hwndOwner=hParent;
 ofn.lpstrFile=nameo;
 ofn.nMaxFile=256;
 ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; //OFN_EXPLORER|OFN_ENABLETEMPLATE|OFN_ENABLEHOOK;
 ofn.lpstrInitialDir=initialdir?initialdir:gfsdir;
 if(GetOpenFileName(&ofn))
 {
  char *tmpdir;

  if((tmpdir=malloc(ofn.nFileOffset+1)))
  {
   strncpy(tmpdir,ofn.lpstrFile,ofn.nFileOffset);
   tmpdir[ofn.nFileOffset]=0;
   AddRecentDir(tmpdir);

   if(!initialdir)              // Prevent setting the File->Open default
                                // directory when a "Recent Directory" is selected.
   {
    if(gfsdir)
     free(gfsdir);
    gfsdir = tmpdir;
   }
   else
    free(tmpdir);
  }
  ALoad(nameo);
 }
}

static uint32 mousex,mousey,mouseb;
void GetMouseData(uint32 *md)
{
 if(FCEUI_IsMovieActive()<0)
   return;

 md[0]=mousex;
 md[1]=mousey;
 if(!fullscreen)
 {
  if(ismaximized)
  {
   RECT t;
   GetClientRect(hAppWnd, &t);
   md[0] = md[0] * VNSWID / (t.right?t.right:1);
   md[1] = md[1] * totallines / (t.bottom?t.bottom:1);
  }
  else
  {
   md[0]/=winsizemulx;
   md[1]/=winsizemuly;
  }
  md[0]+=VNSCLIP;
 }

 md[1]+=srendline;
 md[2]=((mouseb==MK_LBUTTON)?1:0)|((mouseb==MK_RBUTTON)?2:0);
}

//static int sizchange=0;
static int vchanged=0;

extern void RestartMovieOrReset(int pow);


void MapInput(void);

LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
  DSMFix(msg);
  switch(msg) {
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
                  mouseb=wParam;
                  goto proco;
    case WM_MOUSEMOVE:
                  {
                   mousex=LOWORD(lParam);
                   mousey=HIWORD(lParam);
                  }
                  goto proco;
    case WM_ERASEBKGND:
                  if(xbsave)
                   return(0);
                  else goto proco;
    case WM_PAINT:if(xbsave)
                  {
                   PAINTSTRUCT ps;
                   BeginPaint(hWnd,&ps);
                   FCEUD_BlitScreen(xbsave);
                   EndPaint(hWnd,&ps);
                   return(0);
                  }
                  goto proco;
    case WM_SIZE:
                if(!fullscreen && !changerecursive)
                 switch(wParam)
                 {
                  case SIZE_MAXIMIZED: ismaximized = 1;SetMainWindowStuff();break;
                  case SIZE_RESTORED: ismaximized = 0;SetMainWindowStuff();break;
                 }
                 break;
    case WM_SIZING:
                 {
                  RECT *wrect=(RECT *)lParam;
                  RECT srect;

                  int h=wrect->bottom-wrect->top;
                  int w=wrect->right-wrect->left;
                  int how;

                  if(wParam == WMSZ_BOTTOM || wParam == WMSZ_TOP)
                   how = 2;
                  else if(wParam == WMSZ_LEFT || wParam == WMSZ_RIGHT)
                   how = 1;
                  else if(wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT
                        || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT)
                   how = 3;
                  if(how & 1)
                   winsizemulx*= (double)w/winwidth;
                  if(how & 2)
                   winsizemuly*= (double)h/winheight;
                  if(how & 1) FixWXY(0);
                  else FixWXY(1);

                  CalcWindowSize(&srect);
                  winwidth=srect.right;
                  winheight=srect.bottom;
                  wrect->right = wrect->left + srect.right;
                  wrect->bottom = wrect->top + srect.bottom;
                 }
                 //sizchange=1;
                 //break;
                 goto proco;
    case WM_DISPLAYCHANGE:
                if(!fullscreen && !changerecursive)
                 vchanged=1;
                goto proco;
    case WM_DROPFILES:
                {
                 UINT len;
                 char *ftmp;

                 len=DragQueryFile((HANDLE)wParam,0,0,0)+1;
                 if((ftmp=malloc(len)))
                 {
                  DragQueryFile((HANDLE)wParam,0,ftmp,len);
                  ALoad(ftmp);
                  free(ftmp);
                 }
                }
                break;
    case WM_COMMAND:
                if(!(wParam>>16))
                {
                 wParam&=0xFFFF;
                 if(wParam>=600 && wParam<=609) // Recent files
                 {
                  if(rfiles[wParam-600]) ALoad(rfiles[wParam-600]);
                 }
                 else if(wParam >= 700 && wParam <= 709) // Recent dirs
                 {
                  if(rdirs[wParam-700])
                   LoadNewGamey(hWnd, rdirs[wParam - 700]);
                 }
                 switch(wParam)
                 {
				 case 40004:
					 SetAutoFirePattern(1,1);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40005:
					 SetAutoFirePattern(1,2);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40006:
					 SetAutoFirePattern(1,3);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40007:
					 SetAutoFirePattern(1,4);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40008:
					 SetAutoFirePattern(1,5);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40009:
					 SetAutoFirePattern(2,1);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40010:
					 SetAutoFirePattern(2,2);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40011:
					 SetAutoFirePattern(2,3);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40012:
					 SetAutoFirePattern(2,4);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40013:
					 SetAutoFirePattern(3,1);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40014:
					 SetAutoFirePattern(3,2);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40015:
					 SetAutoFirePattern(3,3);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40022:
					 SetAutoFirePattern(4,1);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40023:
					 SetAutoFirePattern(4,2);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40024:
					 SetAutoFirePattern(5,1);
					 CheckedAutoFirePattern = wParam;
					 UpdateMenu();
					 break;
				 case 40031:
				 	 MemToolsUpdateSpeed = 100;
					 CheckedMemToolsUpdateSpeed = wParam;
					 UpdateMenu();
					 break;
				 case 40032:
					 MemToolsUpdateSpeed = 25;
					 CheckedMemToolsUpdateSpeed = wParam;
					 UpdateMenu();
					 break;
				 case 40033:
					 MemToolsUpdateSpeed = 999;
					 CheckedMemToolsUpdateSpeed = wParam;
					 UpdateMenu();
					 break;
				 case 40016:
				 case 40017:
				 case 40018:
				 case 40019:
				 case 40020:
				 case 40021:
					 SetAutoFireOffset(wParam - 40016);
					 CheckedAutoFireOffset = wParam;
					 UpdateMenu();
					 break;
				 case 40025:
					 SetAutoFireDesynch(GetAutoFireDesynch()^1);
					 UpdateMenu();
					 break;
                  case 300:ToggleHideMenu();break;
                  case 301:
					  eoptions^=EO_BGRUN;
					  if((eoptions & EO_BGRUN) == 0)
					  {
						  EnableBackgroundInput = 0;
						  KeyboardSetBackgroundAccess(EnableBackgroundInput);
						  SetJoystickBackgroundAccess(EnableBackgroundInput);
					  }
					  UpdateMenu();
					  break;
				  case 302:EnableBackgroundInput ^= 1;
					  eoptions |= EO_BGRUN*EnableBackgroundInput;
					  KeyboardSetBackgroundAccess(EnableBackgroundInput);
					  SetJoystickBackgroundAccess(EnableBackgroundInput);
					  UpdateMenu();
					  break;
				  case 40029:
					  EnableRewind^= 1;
					  UpdateMenu();
					  break;
				  case 40035:
					  EnableStopMessageInAvi^= 1;
					  FCEUAVI_ShowMovieAVIMessage(EnableStopMessageInAvi);
					  UpdateMenu();
					  break;
				  case 40034:
					  EnablePauseAfterPlayback^= 1;
					  FCEUMOV_ResetStopframe(EnablePauseAfterPlayback);
					  UpdateMenu();
					  break;
				  case 303:status_icon=!status_icon;UpdateMenu();break;
                  case 310:genie^=1;FCEUI_SetGameGenie(genie);UpdateMenu();break;
                  case 311:palyo^=1;
                           FCEUI_SetVidSystem(palyo);
                           RefreshThrottleFPS();
                           UpdateMenu();
                           FixFL();
//						   DoVideoConfigFix();
                           SetMainWindowStuff();
                           break;
				  case 40003: FCEU_SetBotMode(1^FCEU_BotMode());
					          UpdateMenu(); break;
				  case 40002: CreateBasicBot();break;
				  case 40028: DoMemmo(0); break;
                  case 320:StopSound();ConfigDirectories();break;
                  case 327:StopSound();ConfigGUI();break;
                  case 321:StopSound();ConfigInput(hWnd);break;
                  case 322:ConfigTiming();break;
                  case 323:StopSound();ShowNetplayConsole();break;
                  case 324:StopSound();ConfigPalette();break;
                  case 325:StopSound();ConfigSound();break;
                  case 326:ConfigVideo();break;
				  case 328:MapInput();break;

                  case 200:RestartMovieOrReset(0);break;
                  case 201:RestartMovieOrReset(1);break;
				  case 40026: FCEUI_FDSSelect();break;
				  case 40001: FCEUI_FDSInsert();break;
				  case 40027: FCEUI_VSUniCoin();break;
			

		  #ifdef FCEUDEF_DEBUGGER
		  case 203:BeginDSeq(hWnd);break;
		  #endif

                  case 204:ConfigAddCheat(hWnd);break;
                  case 205:CreateMemWatch();break;
                  case 100:StopSound();
                           LoadNewGamey(hWnd, 0);
                           break;
                  case 101:if(GI)
                           {
			    #ifdef FCEUDEF_DEBUGGER
			    KillDebugger();
			    #endif
                            FCEUI_CloseGame();                            
                            GI=0;
                            RedoMenuGI(GI);
                           }
                           break;
                  case 110:FCEUD_SaveStateAs();break;
                  case 111:FCEUD_LoadStateFrom();break;

                  case 120:
                           {
                            MENUITEMINFO mi;
                            char *str;

                            StopSound();
                            if(CreateSoundSave())
                             str="Stop Sound Logging";
                            else
                             str="Log Sound As...";
                            memset(&mi,0,sizeof(mi));
                            mi.fMask=MIIM_DATA|MIIM_TYPE;
                            mi.cbSize=sizeof(mi);
                            GetMenuItemInfo(fceumenu,120,0,&mi);                           
                            mi.fMask=MIIM_DATA|MIIM_TYPE;
                            mi.cbSize=sizeof(mi);
                            mi.dwTypeData=str;
                            mi.cch=strlen(str);
                            SetMenuItemInfo(fceumenu,120,0,&mi);
                           }
                           break;
                  case 130:DoFCEUExit();break;

                  case 141:FCEUD_MovieRecordTo();break;
                  case 142:FCEUD_MovieReplayFrom();break;
                  case 143:FCEUI_StopMovie();break;
                  case 40036:FCEUD_LuaRunFrom(); UpdateMenu(); break;
                  case 40037:FCEU_LuaStop(); UpdateMenu(); break;

				  case 151:FCEUD_AviRecordTo();break;
				  case 152:FCEUD_AviStop();break;

                  case 400:StopSound();ShowAboutBox();break;
                  case 401:MakeLogWindow();break;
                 }
                }
                break;


    case WM_SYSCOMMAND:
               if(GI && wParam == SC_SCREENSAVE && (goptions & GOO_DISABLESS))
                return(0);

               if(wParam==SC_KEYMENU)
               {
                if(GI && InputType[2]==SIFC_FKB && cidisabled)
                 break;
                if(lParam == VK_RETURN || fullscreen || tog) break;
               }
               goto proco;
    case WM_SYSKEYDOWN:
               if(GI && InputType[2]==SIFC_FKB && cidisabled)
                break; /* Hopefully this won't break DInput... */

                if(fullscreen || tog)
                {
                 if(wParam==VK_MENU)
                  break;
                }
                if(wParam==VK_F10)
                {
					return 0;
				/*
                 if(!moocow) FCEUD_PrintError("Iyee");
                 if(!(lParam&0x40000000))
                  FCEUI_ResetNES();
                 break;
				*/
                }

                if(wParam == VK_RETURN)
                {
                 if(!(lParam&(1<<30)))
                 {
                  UpdateMenu();
                  changerecursive=1;
                  if(!SetVideoMode(fullscreen^1))
                   SetVideoMode(fullscreen);
                  changerecursive=0;
                 }
                 break;
                }
                goto proco;

    case WM_KEYDOWN:
              if(GI)
	      {
	       /* Only disable command keys if a game is loaded(and the other
		  conditions are right, of course). */
               if(InputType[2]==SIFC_FKB)
	       {
		if(wParam==VK_SCROLL)
		{
 		 cidisabled^=1;
		 FCEUI_DispMessage("Family Keyboard %sabled.",cidisabled?"en":"dis");
		}
		if(cidisabled)
                 break; /* Hopefully this won't break DInput... */
	       }
	      }
			   /*
               if(!(lParam&0x40000000))
                switch( wParam )
                {
                  case VK_F11:FCEUI_PowerNES();break;
                  case VK_F12:DoFCEUExit();break;
                  //case VK_F2:userpause^=1;break;
                  case VK_F3:ToggleHideMenu();break;
                }
			   */
                goto proco;
    case WM_CLOSE:
    case WM_DESTROY:
    case WM_QUIT:DoFCEUExit();break;
    case WM_ACTIVATEAPP:
       if((BOOL)wParam)
       {
        nofocus=0;
       }
       else
       {
        nofocus=1;
       }
       goto proco;
    case WM_ENTERMENULOOP:
      EnableMenuItem(fceumenu,143,MF_BYCOMMAND | (FCEUI_IsMovieActive()?MF_ENABLED:MF_GRAYED));
      EnableMenuItem(fceumenu,152,MF_BYCOMMAND | (FCEUI_AviIsRecording()?MF_ENABLED:MF_GRAYED));
    default:
      proco:
      return DefWindowProc(hWnd,msg,wParam,lParam);
   }
  return 0;
}

void FixWXY(int pref)
{
   if(eoptions&EO_FORCEASPECT)
   {
    /* First, make sure the ratio is valid, and if it's not, change
       it so that it doesn't break everything.
    */
    if(saspectw < 0.01) saspectw = 0.01;
    if(saspecth < 0.01) saspecth = 0.01;
    if((saspectw / saspecth) > 100) saspecth = saspectw;
    if((saspecth / saspectw) > 100) saspectw = saspecth;

    if((saspectw / saspecth) < 0.1) saspecth = saspectw;
    if((saspecth / saspectw) > 0.1) saspectw = saspecth;

    if(!pref)
    {
     winsizemuly = winsizemulx * 256 / 240 * 3 / 4 * saspectw / saspecth;
    }
    else
    {
     winsizemulx = winsizemuly * 240 / 256 * 4 / 3 * saspecth / saspectw;
    }
   }
   if(winspecial)
   {
    int mult;
    if(winspecial == 1 || winspecial == 2) mult = 2;
    else mult = 3;
    if(winsizemulx < mult)
    {
     if(eoptions&EO_FORCEASPECT)
      winsizemuly *= mult / winsizemulx;
     winsizemulx = mult;
    }
    if(winsizemuly < mult)
    {
     if(eoptions&EO_FORCEASPECT)
      winsizemulx *= mult / winsizemuly;
     winsizemuly = mult;
    }
   }

   if(winsizemulx<0.1)
    winsizemulx=0.1;
   if(winsizemuly<0.1)
    winsizemuly=0.1;

   if(eoptions & EO_FORCEISCALE)
   {
    int x,y;

    x = winsizemulx * 2;
    y = winsizemuly * 2;

    x = (x>>1) + (x&1);
    y = (y>>1) + (y&1);

    if(!x) x=1;
    if(!y) y=1;

    winsizemulx = x;
    winsizemuly = y;
   }

   if(winsizemulx > 100) winsizemulx = 100;
   if(winsizemuly > 100) winsizemuly = 100;
}

void UpdateFCEUWindow(void)
{
//  int w,h;
//  RECT wrect;

  if(vchanged && !fullscreen && !changerecursive && !nofocus)
  {
   SetVideoMode(0);
   vchanged=0;
  }

  BlockingCheck();
  /*#ifdef FCEUDEF_DEBUGGER
  UpdateDebugger();
  #endif*/

  if(!(eoptions&EO_BGRUN))
   while(nofocus)
   {
    StopSound();
    Sleep(75);
    BlockingCheck();
   }
 if(userpause)
 {
  StopSound();
  while(userpause)
  {
   Sleep(50);
   BlockingCheck();
  }
 }
}

void ByebyeWindow(void)
{
 SetMenu(hAppWnd,0);
 DestroyMenu(fceumenu);
 DestroyWindow(hAppWnd);
}

int CreateMainWindow(void)
{
  WNDCLASSEX winclass;
  RECT tmp;

  memset(&winclass,0,sizeof(winclass));
  winclass.cbSize=sizeof(WNDCLASSEX);
  winclass.style=CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS;
  winclass.lpfnWndProc=AppWndProc;
  winclass.cbClsExtra=0;
  winclass.cbWndExtra=0;
  winclass.hInstance=fceu_hInstance;
  winclass.hIcon=LoadIcon(fceu_hInstance, "ICON_1");
  winclass.hIconSm=LoadIcon(fceu_hInstance, "ICON_1");
  winclass.hCursor=LoadCursor(NULL, IDC_ARROW);
  winclass.hbrBackground=GetStockObject(BLACK_BRUSH);
  //winclass.lpszMenuName="FCEUMENU";
  winclass.lpszClassName="FCEULTRA";

  if(!RegisterClassEx(&winclass))
    return FALSE;

  AdjustWindowRectEx(&tmp,WS_OVERLAPPEDWINDOW,1,0);

  fceumenu=LoadMenu(fceu_hInstance,"FCEUMENU");

  recentmenu=CreateMenu();
  recentdmenu = CreateMenu();

  UpdateRMenu(recentmenu, rfiles, 102, 600);
  UpdateRMenu(recentdmenu, rdirs, 103, 700);

  RedoMenuGI(NULL);

  hAppWnd = CreateWindowEx(0,"FCEULTRA","FCE Ultra",
                        WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS,  /* Style */
                        CW_USEDEFAULT,CW_USEDEFAULT,256,240,  /* X,Y ; Width, Height */
                        NULL,fceumenu,fceu_hInstance,NULL );  
  DragAcceptFiles(hAppWnd, 1);
  SetMainWindowStuff();
  return 1;
}


int SetMainWindowStuff(void)
{
  RECT tmp;

  GetWindowRect(hAppWnd,&tmp);

  if(ismaximized)
  {
   winwidth=tmp.right - tmp.left;
   winheight=tmp.bottom - tmp.top;

   ShowWindow(hAppWnd, SW_SHOWMAXIMIZED);
  }
  else
  {
   RECT srect;
   if(WindowXC!=(1<<30))
   {
    /* Subtracting and adding for if(eoptions&EO_USERFORCE) below. */
    tmp.bottom-=tmp.top;
    tmp.bottom+=WindowYC;

    tmp.right-=tmp.left;
    tmp.right+=WindowXC;
   

    tmp.left=WindowXC;
    tmp.top=WindowYC;
    WindowXC=1<<30;
   }

   CalcWindowSize(&srect);
   SetWindowPos(hAppWnd,HWND_TOP,tmp.left,tmp.top,srect.right,srect.bottom,SWP_SHOWWINDOW);
   winwidth=srect.right;
   winheight=srect.bottom;

   ShowWindow(hAppWnd, SW_SHOWNORMAL);
  }
  return 1;
}

int GetClientAbsRect(LPRECT lpRect)
{
  POINT point;
  point.x=point.y=0;
  if(!ClientToScreen(hAppWnd,&point)) return 0;

  lpRect->top=point.y;
  lpRect->left=point.x;
  
  if(ismaximized)
  {
   RECT al;
   GetClientRect(hAppWnd, &al);
   lpRect->right = point.x + al.right;
   lpRect->bottom = point.y + al.bottom;
  }
  else
  {
   lpRect->right=point.x+VNSWID*winsizemulx;
   lpRect->bottom=point.y+totallines*winsizemuly;
  }
  return 1;
}


int LoadPaletteFile(void)
{
 FILE *fp;
 const char filter[]="All usable files(*.pal)\0*.pal\0All files (*.*)\0*.*\0";
 char nameo[2048];
 OPENFILENAME ofn;
 memset(&ofn,0,sizeof(ofn));
 ofn.lStructSize=sizeof(ofn);
 ofn.hInstance=fceu_hInstance;
 ofn.lpstrTitle="FCE Ultra Open Palette File...";
 ofn.lpstrFilter=filter;
 nameo[0]=0;
 ofn.lpstrFile=nameo;
 ofn.nMaxFile=256;
 ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
 ofn.lpstrInitialDir=0;
 if(GetOpenFileName(&ofn))
 {
  if((fp=FCEUD_UTF8fopen(nameo,"rb")))
  {
   fread(cpalette,1,192,fp);
   fclose(fp);
   FCEUI_SetPaletteArray(cpalette);
   eoptions|=EO_CPALETTE;
   return(1);
  }
  else
   FCEUD_PrintError("Error opening palette file!");
 }
 return(0);
}
static HWND pwindow;
static BOOL CALLBACK PaletteConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  DSMFix(uMsg);
  switch(uMsg) {
   case WM_INITDIALOG:                
                if(ntsccol)
                 CheckDlgButton(hwndDlg,100,BST_CHECKED);
                SendDlgItemMessage(hwndDlg,500,TBM_SETRANGE,1,MAKELONG(0,128));
                SendDlgItemMessage(hwndDlg,501,TBM_SETRANGE,1,MAKELONG(0,128));
		FCEUI_GetNTSCTH(&ntsctint,&ntschue);
                SendDlgItemMessage(hwndDlg,500,TBM_SETPOS,1,ntsctint);
                SendDlgItemMessage(hwndDlg,501,TBM_SETPOS,1,ntschue);
                EnableWindow(GetDlgItem(hwndDlg,201),(eoptions&EO_CPALETTE)?1:0);
                break;
   case WM_HSCROLL:
                ntsctint=SendDlgItemMessage(hwndDlg,500,TBM_GETPOS,0,(LPARAM)(LPSTR)0);
                ntschue=SendDlgItemMessage(hwndDlg,501,TBM_GETPOS,0,(LPARAM)(LPSTR)0);
		FCEUI_SetNTSCTH(ntsccol,ntsctint,ntschue);
                break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                if(!(wParam>>16))
                switch(wParam&0xFFFF)
                {
                 case 100:ntsccol^=1;FCEUI_SetNTSCTH(ntsccol,ntsctint,ntschue);break;
                 case 200:
                          StopSound();
                          if(LoadPaletteFile())
                           EnableWindow(GetDlgItem(hwndDlg,201),1);
                          break;
                 case 201:FCEUI_SetPaletteArray(0);
                          eoptions&=~EO_CPALETTE;
                          EnableWindow(GetDlgItem(hwndDlg,201),0);
                          break;
                 case 1:
                        gornk:
                        DestroyWindow(hwndDlg);
                        pwindow=0; // Yay for user race conditions.
                        break;
               }
              }
  return 0;
}

static void ConfigPalette(void)
{
 if(!pwindow)
  pwindow=CreateDialog(fceu_hInstance,"PALCONFIG",0,PaletteConCallB);
 else
  SetFocus(pwindow);
}


static BOOL CALLBACK TimingConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 int x;

  switch(uMsg) {
   case WM_INITDIALOG:                
                if(eoptions&EO_HIGHPRIO)
                 CheckDlgButton(hwndDlg,105,BST_CHECKED);
                if(eoptions&EO_NOTHROTTLE)
                 CheckDlgButton(hwndDlg,101,BST_CHECKED);
                for(x=0;x<10;x++)
                {
                 char buf[8];
                 sprintf(buf,"%d",x);
                 SendDlgItemMessage(hwndDlg,110,CB_ADDSTRING,0,(LPARAM)(LPSTR)buf);
                 SendDlgItemMessage(hwndDlg,111,CB_ADDSTRING,0,(LPARAM)(LPSTR)buf);
                }
                SendDlgItemMessage(hwndDlg,110,CB_SETCURSEL,maxconbskip,(LPARAM)(LPSTR)0);
                SendDlgItemMessage(hwndDlg,111,CB_SETCURSEL,ffbskip,(LPARAM)(LPSTR)0);
                break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                if(!(wParam>>16))
                switch(wParam&0xFFFF)
                {
                 case 1:
                        gornk:
                        if(IsDlgButtonChecked(hwndDlg,105)==BST_CHECKED)
                         eoptions|=EO_HIGHPRIO;
                        else
                         eoptions&=~EO_HIGHPRIO;

                        if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED)
                         eoptions|=EO_NOTHROTTLE;
                        else
                         eoptions&=~EO_NOTHROTTLE;

                        maxconbskip=SendDlgItemMessage(hwndDlg,110,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
                        ffbskip=SendDlgItemMessage(hwndDlg,111,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
                        EndDialog(hwndDlg,0);
                        break;
               }
              }
  return 0;
}

void DoTimingConfigFix(void)
{
  DoPriority();
}

static void ConfigTiming(void)
{
  DialogBox(fceu_hInstance,"TIMINGCONFIG",hAppWnd,TimingConCallB);  
  DoTimingConfigFix();
}

static BOOL CALLBACK GUIConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg) {
   case WM_INITDIALOG:                
                if(eoptions&EO_FOAFTERSTART)
                 CheckDlgButton(hwndDlg,102,BST_CHECKED);
                if(eoptions&EO_HIDEMENU)
                 CheckDlgButton(hwndDlg,104,BST_CHECKED);
                if(goptions & GOO_CONFIRMEXIT)
                 CheckDlgButton(hwndDlg,110,BST_CHECKED);
                if(goptions & GOO_DISABLESS)
                 CheckDlgButton(hwndDlg,111,BST_CHECKED);
                break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                if(!(wParam>>16))
                switch(wParam&0xFFFF)
                {
                 case 1:
                        gornk:
                        if(IsDlgButtonChecked(hwndDlg,102)==BST_CHECKED)
                         eoptions|=EO_FOAFTERSTART;
                        else
                         eoptions&=~EO_FOAFTERSTART;
                        if(IsDlgButtonChecked(hwndDlg,104)==BST_CHECKED)
                         eoptions|=EO_HIDEMENU;
                        else
                         eoptions&=~EO_HIDEMENU;

                        goptions &= ~(GOO_CONFIRMEXIT | GOO_DISABLESS);

                        if(IsDlgButtonChecked(hwndDlg,110)==BST_CHECKED)
                         goptions |= GOO_CONFIRMEXIT;
                        if(IsDlgButtonChecked(hwndDlg,111)==BST_CHECKED)
                         goptions |= GOO_DISABLESS;
                        EndDialog(hwndDlg,0);
                        break;
               }
              }
  return 0;
}

static void ConfigGUI(void)
{
  DialogBox(fceu_hInstance,"GUICONFIG",hAppWnd,GUIConCallB);  
}


static int BrowseForFolder(HWND hParent, char *htext, char *buf)
{
 BROWSEINFO bi;
 LPCITEMIDLIST pidl;
 int ret=1;

 buf[0]=0;

 memset(&bi,0,sizeof(bi));
                
 bi.hwndOwner=hParent;
 bi.lpszTitle=htext;
 bi.ulFlags=BIF_RETURNONLYFSDIRS; 

 if(FAILED(CoInitialize(0)))
  return(0);

 if(!(pidl=SHBrowseForFolder(&bi)))
 {
  ret=0;
  goto end1;
 }

 if(!SHGetPathFromIDList(pidl,buf))
 {
  ret=0;
  goto end2;
 }

 end2:
 /* This probably isn't the best way to free the memory... */
 CoTaskMemFree((PVOID)pidl);

 end1:
 CoUninitialize();
 return(ret);
}

static BOOL CALLBACK DirConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  int x;

  switch(uMsg){
   case WM_INITDIALOG:
                for(x=0;x<9;x++)
                 SetDlgItemText(hwndDlg,100+x,DOvers[x]);
                if(eoptions&EO_SNAPNAME)
                 CheckDlgButton(hwndDlg,300,BST_CHECKED);
                break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                if(!(wParam>>16))
                {
                 if((wParam&0xFFFF)>=200 && (wParam&0xFFFF)<=208)
                 {
                  static char *helpert[9]={"Cheats","Miscellaneous","Nonvolatile Game Data","Save States","Screen Snapshots","FDS BIOS ROM Image","Memory Watch","Basic Bot","Base Directory"};
                  char name[MAX_PATH];

                  if(BrowseForFolder(hwndDlg,helpert[((wParam&0xFFFF)-200)],name))
                   SetDlgItemText(hwndDlg,100+((wParam&0xFFFF)-200),name);
                 }
                 else switch(wParam&0xFFFF)
                 {
                  case 1:
                        gornk:

                        if(IsDlgButtonChecked(hwndDlg,300)==BST_CHECKED)
                         eoptions|=EO_SNAPNAME;
                        else
                         eoptions&=~EO_SNAPNAME;

                        RemoveDirs();   // Remove empty directories.

                        for(x=0;x<9;x++)
                        {
                         LONG len;
                         len=SendDlgItemMessage(hwndDlg,100+x,WM_GETTEXTLENGTH,0,0);
                         if(len<=0)
                         {
                          if(DOvers[x]) free(DOvers[x]);
                          DOvers[x]=0;
                          continue;
                         }
                         len++; // Add 1 for null character.
                         if(!(DOvers[x]=malloc(len)))
                          continue;
                         if(!GetDlgItemText(hwndDlg,100+x,DOvers[x],len))
                         {
                          free(DOvers[x]);
                          DOvers[x]=0;
                          continue;
                         }

                        }

                        CreateDirs();   // Create needed directories.
                        SetDirs();      // Set the directories in the core.
                        EndDialog(hwndDlg,0);
                        break;
                 }
                }
              }
  return 0;
}


static void ConfigDirectories(void)
{
  DialogBox(fceu_hInstance,"DIRCONFIG",hAppWnd,DirConCallB);
}

static int ReplayDialogReadOnlyStatus = 0;
static int ReplayDialogStopFrame = 0;

static char* GetReplayPath(HWND hwndDlg)
{
	char* fn=0;
	char szChoice[MAX_PATH];
	LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0);
	LONG lCount = SendDlgItemMessage(hwndDlg, 200, CB_GETCOUNT, 0, 0);

	// NOTE: lCount-1 is the "Browse..." list item
	if(lIndex != CB_ERR && lIndex != lCount-1)
	{
		LONG lStringLength = SendDlgItemMessage(hwndDlg, 200, CB_GETLBTEXTLEN, (WPARAM)lIndex, 0);
		if(lStringLength < MAX_PATH)
		{
			char szDrive[MAX_PATH]={0};
			char szDirectory[MAX_PATH]={0};
			char szFilename[MAX_PATH]={0};
			char szExt[MAX_PATH]={0};
			char szTemp[MAX_PATH]={0};

			SendDlgItemMessage(hwndDlg, 200, CB_GETLBTEXT, (WPARAM)lIndex, (LPARAM)szTemp);
			if(szTemp[0] && szTemp[1]!=':')
				sprintf(szChoice, ".\\%s", szTemp);
			else
				strcpy(szChoice, szTemp);

			SetCurrentDirectory(BaseDirectory);

			_splitpath(szChoice, szDrive, szDirectory, szFilename, szExt);
			if(szDrive[0]=='\0' && szDirectory[0]=='\0')
				fn=FCEU_MakePath(FCEUMKF_MOVIE, szChoice);		// need to make a full path
			else
				fn=strdup(szChoice);							// given a full path
		}
	}

	return fn;
}

static char* GetRecordPath(HWND hwndDlg)
{
	char* fn=0;
	char szChoice[MAX_PATH];
	char szDrive[MAX_PATH]={0};
	char szDirectory[MAX_PATH]={0};
	char szFilename[MAX_PATH]={0};
	char szExt[MAX_PATH]={0};

	GetDlgItemText(hwndDlg, 200, szChoice, sizeof(szChoice));

	_splitpath(szChoice, szDrive, szDirectory, szFilename, szExt);
	if(szDrive[0]=='\0' && szDirectory[0]=='\0')
		fn=FCEU_MakePath(FCEUMKF_MOVIE, szChoice);		// need to make a full path
	else
		fn=strdup(szChoice);							// given a full path

	return fn;
}

static char* GetSavePath(HWND hwndDlg)
{
	char* fn=0;
	char szDrive[MAX_PATH]={0};
	char szDirectory[MAX_PATH]={0};
	char szFilename[MAX_PATH]={0};
	char szExt[MAX_PATH]={0};
	LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0);
	LONG lStringLength = SendDlgItemMessage(hwndDlg, 301, CB_GETLBTEXTLEN, (WPARAM)lIndex, 0);

	fn = (char*)malloc(lStringLength);
	SendDlgItemMessage(hwndDlg, 301, CB_GETLBTEXT, (WPARAM)lIndex, (LPARAM)fn);

	_splitpath(fn, szDrive, szDirectory, szFilename, szExt);
	if(szDrive[0]=='\0' && szDirectory[0]=='\0')
	{
		char* newfn=FCEU_MakePath(FCEUMKF_STATE, fn);		// need to make a full path
		free(fn);
		fn=newfn;
	}

	return fn;
}


// C:\fceu\movies\bla.fcm  +  C:\fceu\fceu\  ->  C:\fceu\movies\bla.fcm
// movies\bla.fcm  +  fceu\  ->  movies\bla.fcm

// C:\fceu\movies\bla.fcm  +  C:\fceu\  ->  movies\bla.fcm
void AbsoluteToRelative(char *const dst, const char *const dir, const char *const root)
{
	int i, igood=0;

	for(i = 0 ; ; i++)
	{
		int a = tolower(dir[i]);
		int b = tolower(root[i]);
		if(a == '/' || a == '\0' || a == '.') a = '\\';
		if(b == '/' || b == '\0' || b == '.') b = '\\';

		if(a != b)
		{
			igood = 0;
			break;
		}

		if(a == '\\')
			igood = i+1;

		if(!dir[i] || !root[i])
			break;
	}

//	if(igood)
//		sprintf(dst, ".\\%s", dir + igood);
//	else
		strcpy(dst, dir + igood);
}

extern int movieConvertOffset1, movieConvertOffset2,movieConvertOK;
static int movieHackType=3;

static void UpdateReplayDialog(HWND hwndDlg)
{
	movieConvertOffset1=0, movieConvertOffset2=0,movieConvertOK=0;

	int doClear=1;
	char *fn=GetReplayPath(hwndDlg);

	// remember the previous setting for the read-only checkbox
	if(IsWindowEnabled(GetDlgItem(hwndDlg, 201)))
		ReplayDialogReadOnlyStatus = (SendDlgItemMessage(hwndDlg, 201, BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0;

	if(fn)
	{
		MOVIE_INFO info;
		char metadata[MOVIE_MAX_METADATA];
		char rom_name[MAX_PATH];

		memset(&info, 0, sizeof(info));
		info.metadata = metadata;
		info.metadata_size = sizeof(metadata);
		info.name_of_rom_used = rom_name;
		info.name_of_rom_used_size = sizeof(rom_name);

		if(FCEUI_MovieGetInfo(fn, &info))
		{
#define MOVIE_FLAG_NOSYNCHACK          (1<<4) // set in newer version, used for old movie compatibility
			extern int resetDMCacc;
			extern int justAutoConverted;
			int noNoSyncHack=!(info.flags&MOVIE_FLAG_NOSYNCHACK) && resetDMCacc;
			EnableWindow(GetDlgItem(hwndDlg,1000),justAutoConverted || noNoSyncHack);
			EnableWindow(GetDlgItem(hwndDlg,1001),justAutoConverted || noNoSyncHack);
			if(justAutoConverted)
			{
				// use values as nesmock offsets
				if(movieHackType != 0)
				{
					movieHackType=0;
					SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)"2");
					SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)"0");
					SendDlgItemMessage(hwndDlg, 2000, WM_SETTEXT, 0,(LPARAM)"Offset:");
					SendDlgItemMessage(hwndDlg, 2001, WM_SETTEXT, 0,(LPARAM)"from");
				}
			}
			else if(noNoSyncHack)
			{
				// use values as sound reset hack values
				if(movieHackType != 1)
				{
					movieHackType=1;
//					extern int32 DMCacc;
//					extern int8 DMCBitCount;
//					char str[256];
//					sprintf(str, "%d", DMCacc);
//					SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)str);
//					sprintf(str, "%d", DMCBitCount);
//					SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)str);
					SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)"8");
					SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)"0");
					SendDlgItemMessage(hwndDlg, 2000, WM_SETTEXT, 0,(LPARAM)"Missing data: acc=");
					SendDlgItemMessage(hwndDlg, 2001, WM_SETTEXT, 0,(LPARAM)"bc=");
				}
			}
			else if(movieHackType != 2)
			{
				movieHackType=2;
				SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)"");
				SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)"");
				SendDlgItemMessage(hwndDlg, 2000, WM_SETTEXT, 0,(LPARAM)"");
				SendDlgItemMessage(hwndDlg, 2001, WM_SETTEXT, 0,(LPARAM)"");
			}

/*			{	// select away to autoconverted movie... but actually we don't want to do that now that there's an offset setting in the dialog
				extern char lastMovieInfoFilename [512];
				char relative[MAX_PATH];
				AbsoluteToRelative(relative, lastMovieInfoFilename, BaseDirectory);

				LONG lOtherIndex = SendDlgItemMessage(hwndDlg, 200, CB_FINDSTRING, (WPARAM)-1, (LPARAM)relative);
				if(lOtherIndex != CB_ERR)
				{
					// select already existing string
					SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lOtherIndex, 0);
				} else {
					LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0);
					SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, lIndex, (LPARAM)relative);
					SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lIndex, 0);
				}

				// restore focus to the dialog
//				SetFocus(GetDlgItem(hwndDlg, 200));
			}*/


			char tmp[256];
			uint32 div;
			
			sprintf(tmp, "%lu", info.num_frames);
			SetWindowTextA(GetDlgItem(hwndDlg,301), tmp);                   // frames
			SetDlgItemText(hwndDlg,1003,tmp);
			
			div = (FCEUI_GetCurrentVidSystem(0,0)) ? 50 : 60;				// PAL timing
			info.num_frames += (div>>1);                                    // round up
			sprintf(tmp, "%02d:%02d:%02d", (info.num_frames/(div*60*60)), (info.num_frames/(div*60))%60, (info.num_frames/div) % 60);
			SetWindowTextA(GetDlgItem(hwndDlg,300), tmp);                   // length
			
			sprintf(tmp, "%lu", info.rerecord_count);
			SetWindowTextA(GetDlgItem(hwndDlg,302), tmp);                   // rerecord
			
			{
				// convert utf8 metadata to windows widechar
				WCHAR wszMeta[MOVIE_MAX_METADATA];
				if(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, metadata, -1, wszMeta, MOVIE_MAX_METADATA))
				{
					if(wszMeta[0])
						SetWindowTextW(GetDlgItem(hwndDlg,303), wszMeta);              // metadata
					else
						SetWindowTextW(GetDlgItem(hwndDlg,303), L"(this movie has no author info)");				   // metadata
				}
			}
			
			EnableWindow(GetDlgItem(hwndDlg,201),(info.read_only)? FALSE : TRUE); // disable read-only checkbox if the file access is read-only
			SendDlgItemMessage(hwndDlg,201,BM_SETCHECK,info.read_only ? BST_CHECKED : (ReplayDialogReadOnlyStatus ? BST_CHECKED : BST_UNCHECKED), 0);
			
			SetWindowText(GetDlgItem(hwndDlg,306),(info.flags & MOVIE_FLAG_FROM_RESET) ? "Reset or Power-On" : "Savestate");
			if(info.movie_version > 1)
			{
				char emuStr[128];
				SetWindowText(GetDlgItem(hwndDlg,304),info.name_of_rom_used);
				SetWindowText(GetDlgItem(hwndDlg,305),md5_asciistr(info.md5_of_rom_used));
				if(info.emu_version_used > 64)
					sprintf(emuStr, "FCEU %d.%02d.%02d%s", info.emu_version_used/10000, (info.emu_version_used/100)%100, (info.emu_version_used)%100, info.emu_version_used < 9813 ? " (blip)" : "");
				else
				{
					if(info.emu_version_used == 1)
						strcpy(emuStr, "Famtasia");
					else if(info.emu_version_used == 2)
						strcpy(emuStr, "Nintendulator");
					else if(info.emu_version_used == 3)
						strcpy(emuStr, "VirtuaNES");
					else
					{
						strcpy(emuStr, "(unknown)");
						char* dot = strrchr(fn,'.');
						if(dot)
						{
							if(!stricmp(dot,".fmv"))
								strcpy(emuStr, "Famtasia? (unknown version)");
							else if(!stricmp(dot,".nmv"))
								strcpy(emuStr, "Nintendulator? (unknown version)");
							else if(!stricmp(dot,".vmv"))
								strcpy(emuStr, "VirtuaNES? (unknown version)");
							else if(!stricmp(dot,".fcm"))
								strcpy(emuStr, "FCEU? (unknown version)");
						}
					}
				}
				SetWindowText(GetDlgItem(hwndDlg,307),emuStr);
			}
			else
			{
				SetWindowText(GetDlgItem(hwndDlg,304),"unknown");
				SetWindowText(GetDlgItem(hwndDlg,305),"unknown");
				SetWindowText(GetDlgItem(hwndDlg,307),"FCEU 0.98.10 (blip)");
			}

			SetWindowText(GetDlgItem(hwndDlg,308),md5_asciistr(FCEUGameInfo->MD5));
			EnableWindow(GetDlgItem(hwndDlg,1),TRUE);                     // enable OK
			
			doClear = 0;
		}

		free(fn);
	}
	else
	{
		EnableWindow(GetDlgItem(hwndDlg,1000),FALSE);
		EnableWindow(GetDlgItem(hwndDlg,1001),FALSE);
	}

	if(doClear)
	{
		SetWindowText(GetDlgItem(hwndDlg,300),"");
		SetWindowText(GetDlgItem(hwndDlg,301),"");
		SetWindowText(GetDlgItem(hwndDlg,302),"");
		SetWindowText(GetDlgItem(hwndDlg,303),"");
		SetWindowText(GetDlgItem(hwndDlg,304),"");
		SetWindowText(GetDlgItem(hwndDlg,305),"");
		SetWindowText(GetDlgItem(hwndDlg,306),"Nothing (invalid movie)");
		SetWindowText(GetDlgItem(hwndDlg,307),"");
		SetWindowText(GetDlgItem(hwndDlg,308),md5_asciistr(FCEUGameInfo->MD5));
		SetDlgItemText(hwndDlg,1003,"");
		EnableWindow(GetDlgItem(hwndDlg,201),FALSE);
		SendDlgItemMessage(hwndDlg,201,BM_SETCHECK,BST_UNCHECKED,0);
		EnableWindow(GetDlgItem(hwndDlg,1),FALSE);
	}
}



#define MAX(x,y) ((x)<(y)?(y):(x))
#define MIN(x,y) ((x)>(y)?(y):(x))

static BOOL CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_INITDIALOG:
		{
			movieHackType=3;
			SendDlgItemMessage(hwndDlg, 201, BM_SETCHECK, moviereadonly?BST_CHECKED:BST_UNCHECKED, 0);
			SendDlgItemMessage(hwndDlg, 1002,BM_SETCHECK, BST_UNCHECKED, 0);

			char* findGlob[2] = {FCEU_MakeFName(FCEUMKF_MOVIEGLOB, 0, 0),
								 FCEU_MakeFName(FCEUMKF_MOVIEGLOB2, 0, 0)};

			extern int suppress_scan_chunks;
			suppress_scan_chunks=1;

			int i=0, j=0;

			for(j=0;j<2;j++)
			{
				char* temp=0;
				do {
					temp=strchr(findGlob[j],'/');
					if(temp)
						*temp = '\\';
				} while(temp);

				// disabled because... apparently something is case sensitive??
//				for(i=1;i<strlen(findGlob[j]);i++)
//					findGlob[j][i] = tolower(findGlob[j][i]);
			}

//			FCEU_PrintError(findGlob[0]);
//			FCEU_PrintError(findGlob[1]);

			for(j=0;j<2;j++)
			{
				// if the two directories are the same, only look through one of them to avoid adding everything twice
				if(j==1 && !strnicmp(findGlob[0],findGlob[1],MAX(strlen(findGlob[0]),strlen(findGlob[1]))-6))
					continue;

				char globBase[512];
				strcpy(globBase,findGlob[j]);
				globBase[strlen(globBase)-5]='\0';

				extern char FileBase[];
				char szFindPath[512];
				WIN32_FIND_DATA wfd;
				HANDLE hFind;

				memset(&wfd, 0, sizeof(wfd));
				hFind = FindFirstFile(findGlob[j], &wfd);
				if(hFind != INVALID_HANDLE_VALUE)
				{
					do
					{
						if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
							continue;

						// filter out everything that's not *.fcm, *.fmv, *.vmv, or *.nmv
						// (because FindFirstFile is too dumb to do that)
						{
							char* dot=strrchr(wfd.cFileName,'.');
							if(!dot)
								continue;
							char ext [512];
							strcpy(ext, dot+1);
							int k, extlen=strlen(ext);
							for(k=0;k<extlen;k++)
								ext[k]=tolower(ext[k]);
							if(strcmp(ext,"fcm") && strcmp(ext,"fmv") && strcmp(ext,"vmv") && strcmp(ext,"nmv"))
								continue;
						}

						MOVIE_INFO info;
						char metadata[MOVIE_MAX_METADATA];
						char rom_name[MAX_PATH];

						memset(&info, 0, sizeof(info));
						info.metadata = metadata;
						info.metadata_size = sizeof(metadata);
						info.name_of_rom_used = rom_name;
						info.name_of_rom_used_size = sizeof(rom_name);

						char filename [512];
						sprintf(filename, "%s%s", globBase, wfd.cFileName);

						char* dot = strrchr(filename, '.');
						int fcm = (dot && tolower(dot[1]) == 'f' && tolower(dot[2]) == 'c' && tolower(dot[3]) == 'm');

						if(fcm && !FCEUI_MovieGetInfo(filename, &info))
							continue;

						char md51 [256];
						char md52 [256];
						if(fcm) strcpy(md51, md5_asciistr(FCEUGameInfo->MD5));
						if(fcm) strcpy(md52, md5_asciistr(info.md5_of_rom_used));
						if(!fcm || strcmp(md51, md52))
						{
							if(fcm)
							{
								int k, count1=0, count2=0;
								for(k=0;k<strlen(md51);k++) count1 += md51[k]-'0';
								for(k=0;k<strlen(md52);k++) count2 += md52[k]-'0';
								if(count1 && count2)
									continue;
							}

							char* tlen1=strstr(wfd.cFileName, " (");
							char* tlen2=strstr(FileBase, " (");
							int tlen3=tlen1?(int)(tlen1-wfd.cFileName):strlen(wfd.cFileName);
							int tlen4=tlen2?(int)(tlen2-FileBase):strlen(FileBase);
							int len=MAX(0,MIN(tlen3,tlen4));
							if(strnicmp(wfd.cFileName, FileBase, len))
							{
								char temp[512];
								strcpy(temp,FileBase);
								temp[len]='\0';
								if(!strstr(wfd.cFileName, temp))
									continue;
							}
						}

						char relative[MAX_PATH];
						AbsoluteToRelative(relative, filename, BaseDirectory);
						SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, i++, (LPARAM)relative);
					} while(FindNextFile(hFind, &wfd));
					FindClose(hFind);
				}
			}

			suppress_scan_chunks=0;

			free(findGlob[0]);
			free(findGlob[1]);

			if(i>0)
				SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, i-1, 0);
			SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, i++, (LPARAM)"Browse...");

			UpdateReplayDialog(hwndDlg);
		}

		SetFocus(GetDlgItem(hwndDlg, 200));
		return FALSE;

	case WM_COMMAND:
		if(HIWORD(wParam) == CBN_SELCHANGE)
		{
			UpdateReplayDialog(hwndDlg);
		}
		else if(HIWORD(wParam) == CBN_CLOSEUP)
		{
			LONG lCount = SendDlgItemMessage(hwndDlg, 200, CB_GETCOUNT, 0, 0);
			LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0);
			if (lIndex != CB_ERR && lIndex == lCount-1)
				SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDOK, 0);		// send an OK notification to open the file browser
		}
		else
		{
			int wID = LOWORD(wParam);
			switch(wID)
			{
			case IDOK:
				{
					LONG lCount = SendDlgItemMessage(hwndDlg, 200, CB_GETCOUNT, 0, 0);
					LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0);
					if(lIndex != CB_ERR)
					{
						if(lIndex == lCount-1)
						{
							// pop open a file browser...
							char *pn=FCEU_GetPath(FCEUMKF_MOVIE);
							char szFile[MAX_PATH]={0};
							OPENFILENAME ofn;
							int nRet;

							memset(&ofn, 0, sizeof(ofn));
							ofn.lStructSize = sizeof(ofn);
							ofn.hwndOwner = hwndDlg;
							ofn.lpstrFilter = "Supported Movie Files (*.fcm|*.fmv|*.nmv|*.vmv)\0*.fcm;*.fmv;*.nmv;*.vmv\0FCEU Movie Files (*.fcm)\0*.fcm\0Famtasia Movie Files (*.fmv)\0*.fmv\0Nintendulator Movie Files (*.nmv)\0*.nmv\0VirtuaNES Movie Files (*.vmv)\0*.vmv\0All files(*.*)\0*.*\0\0";
							ofn.lpstrFile = szFile;
							ofn.nMaxFile = sizeof(szFile);
							ofn.lpstrInitialDir = pn;
							ofn.Flags = OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
							ofn.lpstrDefExt = "fcm";
							ofn.lpstrTitle = "Replay Movie from File";

							if(GetOpenFileName(&ofn))
							{
								char relative[MAX_PATH];
								AbsoluteToRelative(relative, szFile, BaseDirectory);

								LONG lOtherIndex = SendDlgItemMessage(hwndDlg, 200, CB_FINDSTRING, (WPARAM)-1, (LPARAM)relative);
								if(lOtherIndex != CB_ERR)
								{
									// select already existing string
									SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lOtherIndex, 0);
								} else {
									SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, lIndex, (LPARAM)relative);
									SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lIndex, 0);
								}

								// restore focus to the dialog
								SetFocus(GetDlgItem(hwndDlg, 200));
								UpdateReplayDialog(hwndDlg);
//								if (ofn.Flags & OFN_READONLY)
//									SendDlgItemMessage(hwndDlg, 201, BM_SETCHECK, BST_CHECKED, 0);
//								else
//									SendDlgItemMessage(hwndDlg, 201, BM_SETCHECK, BST_UNCHECKED, 0);
							}

							free(pn);
						}
						else
						{
							// user had made their choice
							// TODO: warn the user when they open a movie made with a different ROM
							char* fn=GetReplayPath(hwndDlg);
							char TempArray[16];
							ReplayDialogReadOnlyStatus = (SendDlgItemMessage(hwndDlg, 201, BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0;
							
							char offset1Str[32]={0};
							char offset2Str[32]={0};
							
							SendDlgItemMessage(hwndDlg, 1003, WM_GETTEXT, (WPARAM)32, (LPARAM)offset1Str);
							ReplayDialogStopFrame = (SendDlgItemMessage(hwndDlg, 1002, BM_GETCHECK,0,0) == BST_CHECKED)? strtol(offset1Str,0,10):0;

							SendDlgItemMessage(hwndDlg, 1000, WM_GETTEXT, (WPARAM)32, (LPARAM)offset1Str);
							SendDlgItemMessage(hwndDlg, 1001, WM_GETTEXT, (WPARAM)32, (LPARAM)offset2Str);

							movieConvertOffset1=strtol(offset1Str,0,10);
							movieConvertOffset2=strtol(offset2Str,0,10);
							movieConvertOK=1;

							EndDialog(hwndDlg, (INT_PTR)fn);
						}
					}
				}
				return TRUE;

			case IDCANCEL:
				EndDialog(hwndDlg, 0);
				return TRUE;
			}
		}

	case WM_CTLCOLORSTATIC:
		if((HWND)lParam == GetDlgItem(hwndDlg, 308))
		{
			// draw the md5 sum in red if it's different from the md5 of the rom used in the replay
			HDC hdcStatic = (HDC)wParam;
			char szMd5Text[35];

			GetDlgItemText(hwndDlg, 305, szMd5Text, 35);
			if(!strlen(szMd5Text) || !strcmp(szMd5Text, "unknown") || !strcmp(szMd5Text, "00000000000000000000000000000000") || !strcmp(szMd5Text, md5_asciistr(FCEUGameInfo->MD5)))
				SetTextColor(hdcStatic, RGB(0,0,0));		// use black color for a match (or no comparison)
			else
				SetTextColor(hdcStatic, RGB(255,0,0));		// use red for a mismatch
			SetBkMode(hdcStatic, TRANSPARENT);
			//return (LONG)GetStockObject(NULL_BRUSH);
			return TRUE;
		}
		else
			return FALSE;
	}

	return FALSE;
};

void FCEUD_MovieReplayFrom(void)
{
  char* fn;
	
  StopSound();

  fn=(char*)DialogBox(fceu_hInstance, "IDD_REPLAYINP", hAppWnd, ReplayDialogProc);
  if(fn)
  {
	  FCEUI_LoadMovie(fn, ReplayDialogReadOnlyStatus, ReplayDialogStopFrame);
	  free(fn);
      palyo=FCEUI_GetCurrentVidSystem(0,0);
      UpdateMenu();
      FixFL();
      SetMainWindowStuff();
      RefreshThrottleFPS();
   
	  extern int movie_readonly;
	  moviereadonly = movie_readonly; // for prefs
  }
}

INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {

	static int *success;

	switch (msg) {
	case WM_INITDIALOG:
		{

		// Nothing very useful to do
		success = (int*)lParam;
		return TRUE;
		}
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
			case IDOK:
			{
				char filename[MAX_PATH];
				GetDlgItemText(hDlg, 1096, filename, MAX_PATH);
				if (FCEU_LoadLuaCode(filename)) {
					*success = 1;
					// For user's convenience, don't close dialog unless we're done.
					// Users who make syntax errors and fix/reload will thank us.
					EndDialog(hDlg, 1);
				} else {
					//MessageBox(hDlg, "Couldn't load script.", "Oops", MB_OK); // XXX better if errors are displayed by the Lua code.
					*success = 0;
				}
				return TRUE;
			}
			case IDCANCEL:
			{
				EndDialog(hDlg, 0);
				return TRUE;
			}
			case 1359:
			{
				OPENFILENAME  ofn;
				char  szFileName[MAX_PATH];
				szFileName[0] = '\0';
				ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) );
				ofn.lStructSize = sizeof(OPENFILENAME);
				ofn.hwndOwner = hDlg;
				ofn.lpstrFilter = "Lua scripts\0*.lua\0All files\0*.*\0\0";
				ofn.lpstrFile = szFileName;
				ofn.lpstrDefExt = "lua";
				ofn.nMaxFile = MAX_PATH;
				ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; // hide previously-ignored read-only checkbox (the real read-only box is in the open-movie dialog itself)
				if(GetOpenFileName( &ofn ))
				{
					SetWindowText(GetDlgItem(hDlg, 1096), szFileName);
				}
				//SetCurrentDirectory(movieDirectory);
				return TRUE;
			}
		}


	}
	char message[1024];
//	sprintf(message, "Unkonwn command %d,%d",msg,wParam);
	//MessageBox(hDlg, message, TEXT("Range Error"), MB_OK);

//	printf("Unknown entry %d,%d,%d\n",msg,wParam,lParam);
	// All else, fall off
	return FALSE;

}

void FCEUD_LuaRunFrom(void)
{
  int success = 0;

  StopSound();

  DialogBoxParam(fceu_hInstance, "IDD_LUA_ADD", hAppWnd, DlgLuaScriptDialog,(LPARAM) &success);
}

static void UpdateRecordDialogPath(HWND hwndDlg, const char* fname)
{
	char* baseMovieDir = FCEU_GetPath(FCEUMKF_MOVIE);
	char* fn=0;

	// display a shortened filename if the file exists in the base movie directory
	if(!strncmp(fname, baseMovieDir, strlen(baseMovieDir)))
	{
		char szDrive[MAX_PATH]={0};
		char szDirectory[MAX_PATH]={0};
		char szFilename[MAX_PATH]={0};
		char szExt[MAX_PATH]={0};
		
		_splitpath(fname, szDrive, szDirectory, szFilename, szExt);
		fn=(char*)malloc(strlen(szFilename)+strlen(szExt)+1);
		_makepath(fn, "", "", szFilename, szExt);
	}
	else
		fn=strdup(fname);

	if(fn)
	{
		SetWindowText(GetDlgItem(hwndDlg,200),fn);				// FIXME:  make utf-8?
		free(fn);
	}
}

static void UpdateRecordDialog(HWND hwndDlg)
{
	int enable=0;
	char* fn=0;

	fn=GetRecordPath(hwndDlg);

	if(fn)
	{
		if(access(fn, F_OK) ||
			!access(fn, W_OK))
		{
			LONG lCount = SendDlgItemMessage(hwndDlg, 301, CB_GETCOUNT, 0, 0);
			LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0);
			if(lIndex != lCount-1)
			{
				enable=1;
			}
		}

		free(fn);
	}

	EnableWindow(GetDlgItem(hwndDlg,1),enable ? TRUE : FALSE);
}

struct CreateMovieParameters
{
	char* szFilename;				// on Dialog creation, this is the default filename to display.  On return, this is the filename that the user chose.
	int recordFrom;				// 0 = "Power-On", 1 = "Reset", 2 = "Now", 3+ = savestate file in szSavestateFilename
	char* szSavestateFilename;
	WCHAR metadata[MOVIE_MAX_METADATA];
};

static BOOL CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static struct CreateMovieParameters* p = NULL;
	
	switch(uMsg)
	{
	case WM_INITDIALOG:
		p = (struct CreateMovieParameters*)lParam;
		UpdateRecordDialogPath(hwndDlg, p->szFilename);
		free(p->szFilename);
		
		/* Populate the "record from..." dialog */
		{
			char* findGlob=FCEU_MakeFName(FCEUMKF_STATEGLOB, 0, 0);
			WIN32_FIND_DATA wfd;
			HANDLE hFind;
			int i=0;
			
			SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Start");
			SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Reset");
			SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Now");
			
			memset(&wfd, 0, sizeof(wfd));
			hFind = FindFirstFile(findGlob, &wfd);
			if(hFind != INVALID_HANDLE_VALUE)
			{
				do
				{
					if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
						(wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
						continue;
					
					if (strlen(wfd.cFileName) < 4 ||
						!strcmp(wfd.cFileName + (strlen(wfd.cFileName) - 4), ".fcm"))
						continue;

					SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)wfd.cFileName);
				} while(FindNextFile(hFind, &wfd));
				FindClose(hFind);
			}
			free(findGlob);
			
			SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Browse...");
			SendDlgItemMessage(hwndDlg, 301, CB_SETCURSEL, 0, 0);				// choose "from reset" as a default
		}
		UpdateRecordDialog(hwndDlg);
		
		return TRUE;
		
	case WM_COMMAND:
		if(HIWORD(wParam) == CBN_SELCHANGE)
		{
			LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0);
			if(lIndex == CB_ERR)
			{
				// fix listbox selection
				SendDlgItemMessage(hwndDlg, 301, CB_SETCURSEL, (WPARAM)0, 0);
			}
			UpdateRecordDialog(hwndDlg);
			return TRUE;
		}
		else if(HIWORD(wParam) == CBN_CLOSEUP)
		{
			LONG lCount = SendDlgItemMessage(hwndDlg, 301, CB_GETCOUNT, 0, 0);
			LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0);
			if (lIndex != CB_ERR && lIndex == lCount-1)
			{
				OPENFILENAME ofn;
				char szChoice[MAX_PATH]={0};
				
				// pop open a file browser to choose the savestate
				memset(&ofn, 0, sizeof(ofn));
				ofn.lStructSize = sizeof(ofn);
				ofn.hwndOwner = hwndDlg;
				ofn.lpstrFilter = "FCE Ultra Save State(*.fc?)\0*.fc?\0\0";
				ofn.lpstrFile = szChoice;
				ofn.lpstrDefExt = "fcs";
				ofn.nMaxFile = MAX_PATH;
				if(GetOpenFileName(&ofn))
				{
					SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, lIndex, (LPARAM)szChoice);
					SendDlgItemMessage(hwndDlg, 301, CB_SETCURSEL, (WPARAM)lIndex, 0);
				}
				else
					UpdateRecordDialog(hwndDlg);
			}
			return TRUE;
		}
		else if(HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == 200)
		{
			UpdateRecordDialog(hwndDlg);
		}
		else
		{
			switch(LOWORD(wParam))
			{
			case IDOK:
				{
					LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0);
					p->szFilename = GetRecordPath(hwndDlg);
					GetDlgItemTextW(hwndDlg,300,p->metadata,MOVIE_MAX_METADATA);
					p->recordFrom = (int)lIndex;
					if(lIndex>=3)
						p->szSavestateFilename = GetSavePath(hwndDlg);
					EndDialog(hwndDlg, 1);
				}
				return TRUE;
				
			case IDCANCEL:
				EndDialog(hwndDlg, 0);
				return TRUE;
				
			case 201:
				{
					OPENFILENAME ofn;
					char szChoice[MAX_PATH]={0};
					
					// browse button
					memset(&ofn, 0, sizeof(ofn));
					ofn.lStructSize = sizeof(ofn);
					ofn.hwndOwner = hwndDlg;
					ofn.lpstrFilter = "FCE Ultra Movie File(*.fcm)\0*.fcm\0All files(*.*)\0*.*\0\0";
					ofn.lpstrFile = szChoice;
					ofn.lpstrDefExt = "fcm";
					ofn.nMaxFile = MAX_PATH;
					ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
					if(GetSaveFileName(&ofn))
						UpdateRecordDialogPath(hwndDlg,szChoice);
				}
				return TRUE;
			}
		}
	}

	return FALSE;
}

void FCEUD_MovieRecordTo(void)
{
	struct CreateMovieParameters p;
	p.szFilename=FCEUI_MovieGetCurrentName(0);
	
	StopSound();

	if(DialogBoxParam(fceu_hInstance,"IDD_RECORDINP",hAppWnd,RecordDialogProc,(LPARAM)&p))
	{
		// turn WCHAR into UTF8
		char meta[MOVIE_MAX_METADATA<<2];
		WideCharToMultiByte(CP_UTF8, 0, p.metadata, -1, meta, sizeof(meta), NULL, NULL);

		if(p.recordFrom >= 3)
		{
			// attempt to load the savestate
			// FIXME:  pop open a messagebox if this fails
			FCEUI_LoadState(p.szSavestateFilename);
			{
				extern int loadStateFailed;
				if(loadStateFailed)
				{
					char str [1024];
					sprintf(str, "Failed to load save state \"%s\".\nRecording from current state instead...", p.szSavestateFilename);
					FCEUD_PrintError(str);
				}
			}
			free(p.szSavestateFilename);
		}

		FCEUI_SaveMovie(p.szFilename, (p.recordFrom==0) ? MOVIE_FLAG_FROM_POWERON : ((p.recordFrom==1) ? MOVIE_FLAG_FROM_RESET : 0), meta);
	}

	free(p.szFilename);
}

void FCEUD_AviRecordTo(void)
{
	OPENFILENAME ofn;
	char szChoice[MAX_PATH];

	if(FCEUMOV_IsPlaying())
	{
		extern char curMovieFilename[];
		strcpy(szChoice, curMovieFilename);
		char* dot=strrchr(szChoice,'.');
		if(dot) *dot='\0';
		strcat(szChoice,".avi");
	}
	else
	{
		extern char FileBase[];
		sprintf(szChoice, "%s.avi", FileBase);
	}

	StopSound();

	// avi record file browser
	memset(&ofn, 0, sizeof(ofn));
	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = hAppWnd;
	ofn.lpstrFilter = "AVI Files (*.avi)\0*.avi\0\0";
	ofn.lpstrFile = szChoice;
	ofn.lpstrDefExt = "avi";
	ofn.lpstrTitle = "Save AVI as";

	ofn.nMaxFile = MAX_PATH;
	ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
	if(GetSaveFileName(&ofn))
	{
		FCEUI_AviBegin(szChoice);
	}
}

void FCEUD_AviStop(void)
{
	FCEUI_AviEnd();
}

void FCEUD_CmdOpen(void)
{
	StopSound();
	LoadNewGamey(hAppWnd, 0);
}

